/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.navid.trafalgar.model.opengl2;

import com.jme3.asset.AssetManager;
import com.jme3.input.InputManager;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.AnalogListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.material.Material;
import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.renderer.queue.RenderQueue.Bucket;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Box;
import com.navid.trafalgar.model.AShipModel;

/**
 *
 * @author alberto
 */
public class ShipModel extends AShipModel {

    @Override
    public float getOrientation() {
        return shipOrientation.getAngle();
    }
    private boolean previousTransparent = false;

    @Override
    public void setTransparent(boolean b) {
        if (!previousTransparent && b) {
            matHull.getAdditionalRenderState().setBlendMode(BlendMode.Color); // activate transparency
            matSail.getAdditionalRenderState().setBlendMode(BlendMode.Color); // activate transparency
            previousTransparent = true;

        } else if (!b && previousTransparent) {
            matHull.getAdditionalRenderState().setBlendMode(BlendMode.Off); // activate transparency
            matSail.getAdditionalRenderState().setBlendMode(BlendMode.Off); // activate transparency
            previousTransparent = false;
        }
    }

    private class Sail {

        private Vector2f orientation = new Vector2f(1, 0);
        private Node spatialSail = new Node();

        private Sail(AssetManager assetManager) {
            Geometry geoSail = new Geometry("vela", new Box(0.1f, 13f, 13f));

            spatialSail.attachChild(geoSail);
            spatialSail.setLocalTranslation(6, 25, 4);

        }

        public Vector2f getLocalOrientation() {
            return orientation;
        }

        public float getGlobalRadians() {
            return orientation.getAngle() + shipOrientation.getAngle();
        }

        public void setLocalOrientation(Vector2f newOrientation) {
            float radians = this.orientation.angleBetween(newOrientation);
            rotate(radians);
        }

        public void rotate(float radians) {
            orientation.rotateAroundOrigin(radians, true);
            spatialSail.rotate(0, radians, 0);
        }

        public Spatial getSpatial() {
            return spatialSail;
        }
    }

    private class Rudder {

        private Vector2f orientation = new Vector2f(1, 0);

        private Rudder(AssetManager assetManager) {
        }

        public Vector2f getLocalOrientation() {
            return orientation;
        }

        public float getGlobalRadians() {
            return orientation.getAngle() + shipOrientation.getAngle();
        }

        public void setLocalOrientation(Vector2f newOrientation) {
            float radians = this.orientation.angleBetween(newOrientation);
            rotate(radians);
        }

        public void rotate(float radians) {
            orientation.rotateAroundOrigin(radians, true);
        }
    }
    private Spatial spatial;
    private Sail sail;
    private Rudder rudder;
    private Vector2f shipOrientation = new Vector2f(1, 0);
    private float speed = 0f;
    private Material matHull;
    private Material matSail;

    public ShipModel(AssetManager assetManager) {
        super();
        spatial = assetManager.loadModel("Models/s2/s2.j3o");
        spatial.rotate(0f, (float) -Math.PI / 2, 0f);
        this.attachChild(spatial);

        sail = new Sail(assetManager);
        this.attachChild(sail.getSpatial());

        rudder = new Rudder(assetManager);

        spatial.setQueueBucket(Bucket.Transparent);
        sail.getSpatial().setQueueBucket(Bucket.Transparent);
    }

    @Override
    public void update(float tpf) {

        if (rudder.getLocalOrientation().getAngle() < 0) {
            rudder.rotate(-0.005f * tpf);
        } else {
            rudder.rotate(0.005f * tpf);
        }

        Vector3f physicsLocation = this.getLocalTranslation();

        Vector2f windDirection = context.getWind().getWind();

        double windOverVela = Math.cos(sail.getGlobalRadians() - windDirection.getAngle());
        double velaOverShip = Math.cos(shipOrientation.getAngle() - sail.getGlobalRadians());

        float speed_gain = (float) (windDirection.length() * windOverVela * velaOverShip);

        speed = (speed * 500 + speed_gain) / 501;

        shipOrientation.rotateAroundOrigin(rudder.getLocalOrientation().getAngle() * speed, true);
        this.rotate(0, rudder.getLocalOrientation().getAngle() * speed, 0);

        this.move(shipOrientation.x * speed, 0, shipOrientation.y * speed);

    }
    private AnalogListener analogListener = new AnalogListener() {

        public void onAnalog(String name, float value, float tpf) {
            RotateSimpleWind wind = (RotateSimpleWind) context.getWind();

            if (name.equals("SHIP_RudderRight")) {
                rudder.rotate(0.01f * tpf);
            }
            if (name.equals("SHIP_RudderLeft")) {
                rudder.rotate(-0.01f * tpf);
            }
            if (name.equals("SHIP_SailRight")) {
                sail.rotate(0.5f * tpf);
            }
            if (name.equals("SHIP_SailLeft")) {
                sail.rotate(-0.5f * tpf);
            }

        }
    };

    @Override
    public void registerInput(InputManager inputManager) {
        inputManager.addMapping("SHIP_RudderRight", new KeyTrigger(KeyInput.KEY_T));
        inputManager.addMapping("SHIP_RudderLeft", new KeyTrigger(KeyInput.KEY_R));
        inputManager.addMapping("SHIP_SailRight", new KeyTrigger(KeyInput.KEY_F));
        inputManager.addMapping("SHIP_SailLeft", new KeyTrigger(KeyInput.KEY_G));
        inputManager.addListener(analogListener, new String[]{"SHIP_RudderRight", "SHIP_RudderLeft", "SHIP_SailRight", "SHIP_SailLeft"});

    }

    @Override
    public float getSpeed() {
        return speed;
    }

    public void setSailMaterial(Material mat) {
        matSail = mat;
        sail.getSpatial().setMaterial(mat);
    }

    public void setHullMaterial(Material mat) {
        matHull = mat;
        spatial.setMaterial(mat);
    }
}
